package com.wuhao.code.check.inspection.inspections

import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.lang.Language
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElementVisitor
import com.wuhao.code.check.constants.Annotations
import com.wuhao.code.check.constants.InspectionNames.AUTOWIRED
import com.wuhao.code.check.hasAnnotation
import com.wuhao.code.check.inspection.visitor.BaseCodeFormatVisitor
import com.wuhao.code.check.style.arrangement.kotlin.KotlinRecursiveVisitor
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.base.psi.replaced
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.createPrimaryConstructorIfAbsent
import org.jetbrains.kotlin.psi.psiUtil.containingClass
import org.jetbrains.kotlin.psi.psiUtil.isPrivate

/**
 *
 * Created by Dell on 2024-09-30.
 *
 * @author Dell
 */
class AutowiredInspection : BaseInspection(AUTOWIRED) {

  override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
    return Visitor(holder)
  }

}

private class Visitor(private val holder: ProblemsHolder) : KotlinRecursiveVisitor(), BaseCodeFormatVisitor {

  override fun support(language: Language): Boolean {
    return language is KotlinLanguage
  }

  override fun visitProperty(property: KtProperty, data: Any?): Any? {
    if (property.hasAnnotation(Annotations.AUTOWIRED)) {
      holder.registerProblem(property, "[Check]不建议使用@Autowired注解", ProblemHighlightType.WARNING, Fix())
    }
    return super.visitProperty(property, data)
  }

}

private class Fix : LocalQuickFix {

  override fun getFamilyName(): String {
    return "[Check]不建议使用@Autowired注解"
  }

  override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
    val element = descriptor.psiElement
    if (element is KtProperty) {
      // 把所有使用@Autowired注解的属性移动到构造函数中
      val containingClass = element.containingClass() ?: return
      val factory = KtPsiFactory(project)

      val autowiredProperties = containingClass.getProperties().filter { it.hasAnnotation(Annotations.AUTOWIRED) }

      val constructorParams =
          autowiredProperties.joinToString(", ") { "${if (it.isPrivate()) {
            "private"
          } else {
            ""
          }
          } val ${it.name}: ${it.typeReference?.text}" }

      // Create the default constructor
      containingClass.createPrimaryConstructorIfAbsent()
      val existsParamtersText = containingClass.primaryConstructor?.valueParameterList?.text?.drop(1)?.dropLast(1) ?: ""
      if (existsParamtersText.isBlank()) {
        val newConstructor = factory.createPrimaryConstructor("($constructorParams)")
        containingClass.primaryConstructor?.replaced(newConstructor)
      } else {
        val newConstructor = factory.createPrimaryConstructor("(${existsParamtersText},\n$constructorParams)")
        containingClass.primaryConstructor?.replaced(newConstructor)
      }
      autowiredProperties.forEach {
        it.delete()
      }
    }
  }

}
